package pl.diagnoser.client;

import java.util.ArrayList;
import java.util.List;
import pl.diagnoser.client.dto.DefectDictDTO;
import pl.diagnoser.client.dto.EstimateDTO;
import pl.diagnoser.client.dto.ObjectsDTO;
import pl.diagnoser.client.dto.SymptomDTO;
import pl.diagnoser.client.tools.DataGetterService;
import pl.diagnoser.client.tools.DataGetterServiceAsync;
import pl.diagnoser.client.tools.DiagnoserProperties;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsDate;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.ListGridFieldType;
import com.smartgwt.client.types.TitleOrientation;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.Button;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.events.DoubleClickEvent;
import com.smartgwt.client.widgets.events.DoubleClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.SpinnerItem;
import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
import com.smartgwt.client.widgets.grid.CellFormatter;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;

public class AddNewObjectEstimateLayout extends Canvas {

	private DiagnoserProperties properties = new DiagnoserProperties();
	private ObjectsDTO object;
	private ObjectHandling parentLayout;
	private Window window;
	private EstimateSymptomsData estimateSymptomsData = new EstimateSymptomsData();
	private EstimateSymptomsData defectsData = new EstimateSymptomsData();
	private static DataGetterServiceAsync dataGetterAsc = GWT.create(DataGetterService.class);
	private ListGrid defectsGrid = new ListGrid();

	AddNewObjectEstimateLayout( Window window, ObjectHandling parentLayout, ObjectsDTO object ) {
		super();
		this.object = object;
		this.parentLayout = parentLayout;
		this.window = window;
	}

	public Canvas initLayout() {
		VLayout mainLayout = new VLayout();
		mainLayout.setWidth100();
		mainLayout.setHeight100();
		mainLayout.setMargin(5);
		mainLayout.setPadding(2);

		mainLayout.addMember(objectDetailLayout());

		this.addChild(mainLayout);
		return this;
	}

	private VLayout objectSymptomsLayout() {

		final VLayout estimatesDetailsLayout = new VLayout();
		estimatesDetailsLayout.setWidth(400);
		estimatesDetailsLayout.setHeight100();
		estimatesDetailsLayout.setMembersMargin(5);

		HLayout addButtonsLayout = new HLayout();
		addButtonsLayout.setWidth(380);
		addButtonsLayout.setHeight(50);

		final DynamicForm symptomsForm = new DynamicForm();
		symptomsForm.setWidth(240);
		symptomsForm.setHeight100();
		symptomsForm.setTitleOrientation(TitleOrientation.TOP);

        final SelectItem symptomsSelector = new SelectItem();
        symptomsSelector.setName("symptomsSelector");
        symptomsSelector.setDefaultValue("--- Wybierz z listy ---");

        symptomsSelector.setTitle("symptomsSelector");
        properties.getFormItemTitle("symptomsSelector", symptomsSelector);

        symptomsSelector.setWidth(170);
        Dictionary.getInstance().loadSymptomsToCombo(symptomsSelector);

        final SpinnerItem symptomConfidence = new SpinnerItem("symptomConfidence");
        properties.getFormItemTitle("symptomConfidence", symptomConfidence);

        symptomConfidence.setType("double");

        Double minValue = new Double(NumberFormat.getFormat("#.##").format((double) 0.1));
        Double maxValue = new Double(NumberFormat.getFormat("#.##").format((double) 1));
        symptomConfidence.setMin(minValue);
		symptomConfidence.setDefaultValue(minValue);
		symptomConfidence.setStep(minValue);
        symptomConfidence.setMax(maxValue);
        symptomConfidence.setWidth(60);

        symptomsForm.setFields(new FormItem[] {symptomsSelector, symptomConfidence});

        final ListGrid symptomsGrid = new ListGrid();

        final Button addSymptom = new Button("addSymptom");
        properties.getWidgetTitle("addSymptom", addSymptom);

        addSymptom.setWidth(135);
        addSymptom.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				Double confidence = null;
				if(symptomConfidence.getValue() instanceof Integer)
					confidence = new Double(NumberFormat.getFormat("#.##").format((Integer) symptomConfidence.getValue()));
				else
					confidence = new Double(NumberFormat.getFormat("#.##").format((Float) symptomConfidence.getValue()));


				estimateSymptomsData.addRecord(new EstimatesSymptomsRecord(
						symptomsSelector.getDisplayValue(),
						confidence
						));
				symptomsGrid.setData(estimateSymptomsData.getRecords().toArray
						(new EstimatesSymptomsRecord[estimateSymptomsData.getRecords().size()]));

				refreshDefectsList();
			}
		});
        addSymptom.setDisabled(true);

        symptomsSelector.addChangedHandler( new ChangedHandler() {
			public void onChanged(ChangedEvent event) {
				addSymptom.setDisabled(false);
			}
		});

        addButtonsLayout.addMember(symptomsForm);
        addButtonsLayout.addMember(addSymptom);

		ListGridField rowNum = new ListGridField("symptomNum", "LP");
        rowNum.setType(ListGridFieldType.INTEGER);
        rowNum.setWidth(50);
        rowNum.setCellFormatter(new CellFormatter() {
            public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
            	return rowNum + 1 + "";
            }
        });
        ListGridField estimateSymptoms = new ListGridField("symptom", "symptomsGrid.symptom");
        ListGridField estimateConfidence = new ListGridField("confidence","symptomsGrid.confidence",  90);
        estimateConfidence.setType(ListGridFieldType.FLOAT);

        symptomsGrid.setWidth(380);
        symptomsGrid.setHeight100();
        symptomsGrid.setFields(rowNum, estimateSymptoms, estimateConfidence);
        properties.getListGridTitle("symptom", "symptomsGrid", symptomsGrid, true);
        properties.getListGridTitle("confidence", "symptomsGrid", symptomsGrid, true);

		//estimatesDetailsLayout.addMember(estimateDetailsLabel);
		estimatesDetailsLayout.addMember(addButtonsLayout);
		estimatesDetailsLayout.addMember(symptomsGrid);

		return estimatesDetailsLayout;
	}

	private HLayout objectDetailLayout() {

		HLayout mainDetailsLayout = new HLayout();
		mainDetailsLayout.setWidth100();
		mainDetailsLayout.setHeight100();
		mainDetailsLayout.setMembersMargin(10);

		//Layout na dane szczegółowe o obiekcie oraz symptomy
		final VLayout objectDetailsLayout = new VLayout();
		objectDetailsLayout.setWidth(390);
		objectDetailsLayout.setHeight(400);

		final Label infoLabel = new Label();
		infoLabel.setAlign(Alignment.LEFT);
		infoLabel.setTop(5);
		infoLabel.setHeight(20);
		infoLabel.setWidth100();

		infoLabel.setContents("infoLabel");
		properties.getLabelTitle("infoLabel", infoLabel);

		ObjectDetailsForm form = new ObjectDetailsForm(object,false, true, false);
		form.setWidth(400);
		form.setHeight(90);

		final Label estimateDetailsLabel = new Label();
		estimateDetailsLabel.setTop(5);
		estimateDetailsLabel.setHeight(20);

		estimateDetailsLabel.setContents("estimateDetailsLabel");
		properties.getLabelTitle("estimateDetailsLabel", estimateDetailsLabel);

		objectDetailsLayout.addMember(infoLabel);
		//objectDetailsLayout.addMember(objectDetailsLayout);
		objectDetailsLayout.addMember(estimateDetailsLabel);
		objectDetailsLayout.addMember(objectSymptomsLayout());

		//Layout na rezultat wizyty
		VLayout defectLayout = new VLayout();
		defectLayout.setWidth100();
		defectLayout.setHeight(400);
		defectLayout.setMembersMargin(15);

		final Label defectLabel = new Label();
		defectLabel.setAlign(Alignment.LEFT);
		defectLabel.setTop(5);
		defectLabel.setHeight(20);
		defectLabel.setWidth100();

		defectLabel.setContents("defectLabel");
		properties.getLabelTitle("defectLabel", defectLabel);

		ListGridField rowNum = new ListGridField("defectNum", "LP");
        rowNum.setType(ListGridFieldType.INTEGER);
        rowNum.setWidth(50);
        rowNum.setCellFormatter(new CellFormatter() {
            public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
            	return rowNum + 1 + "";
            }
        });
        final SelectItem defectSelector = new SelectItem();

        //HACK - symptom i confidence zeby mozna bylo wykorzystac jedna klase
        ListGridField estimateDefect = new ListGridField("symptom", "defectsGrid.symptom");
        ListGridField defectConfidence = new ListGridField("confidence","defectsGrid.confidence",  80);
        defectConfidence.setType(ListGridFieldType.FLOAT);
        defectsGrid.setWidth(325);
        defectsGrid.setHeight100();
        defectsGrid.addDoubleClickHandler(new DoubleClickHandler() {
			public void onDoubleClick(DoubleClickEvent event) {
				EstimatesSymptomsRecord record = (EstimatesSymptomsRecord)((ListGrid)event.getSource()).getSelectedRecord();
				defectSelector.setValue(record.getFieldValue("symptom"));
			}
		});

        defectsGrid.setFields(rowNum, estimateDefect, defectConfidence);
		properties.getListGridTitle("symptom", "defectsGrid", defectsGrid, true);
		properties.getListGridTitle("confidence", "defectsGrid", defectsGrid, true);

        final DynamicForm defectsForm = new DynamicForm();

        defectSelector.setName("defectSelector");
        defectSelector.setDefaultValue("--- Wybierz z listy ---");

        defectSelector.setTitle("defectSelector");
        properties.getFormItemTitle("defectSelector", defectSelector);

        defectSelector.setWidth(170);
        Dictionary.getInstance().loadDefectsToCombo(defectSelector);

        defectsForm.setFields(new FormItem[] {defectSelector});

        HLayout saveButtonsLayout = new HLayout();
        saveButtonsLayout.setWidth100();
        saveButtonsLayout.setHeight(40);
        saveButtonsLayout.setAlign(Alignment.CENTER);
        saveButtonsLayout.setMembersMargin(20);

        Button saveEstimate = new Button("saveEstimate");
        properties.getWidgetTitle("saveEstimate", saveEstimate);
        
        saveEstimate.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				String diagnoza = defectSelector.getDisplayValue();
				if(diagnoza.contains("--"))
					diagnoza = "brak";
				EstimateDTO newEstimate = new EstimateDTO(
						JsDate.create().toLocaleDateString().replace(".", "/"),
						object,
						diagnoza);

				saveEstimate(newEstimate, estimateSymptomsData.getRecordsAsSymptoms());
			}
		});
		
        Button cancelEstimate = new Button("cancelEstimate");
        properties.getWidgetTitle("cancelEstimate", cancelEstimate);

        cancelEstimate.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				window.destroy();
			}
		});

        saveButtonsLayout.addMember(saveEstimate);
        saveButtonsLayout.addMember(cancelEstimate);

        defectLayout.addMember(defectLabel);
        defectLayout.addMember(defectsGrid);
        defectLayout.addMember(defectsForm);
        defectLayout.addMember(saveButtonsLayout);

		mainDetailsLayout.addMember(objectDetailsLayout);
		mainDetailsLayout.addMember(defectLayout);
		return mainDetailsLayout;
	}
	
	private void refreshDefectsList() {
		if (dataGetterAsc == null) {
			dataGetterAsc = GWT.create(DataGetterService.class);
		}
		AsyncCallback<List<DefectDictDTO>> callback = new AsyncCallback<List<DefectDictDTO>>() {

			public void onFailure(Throwable caught) {
				System.out.println(caught.getMessage());
			}

			public void onSuccess(List<DefectDictDTO> result) {
				defectsData.clearRecords();
				if(result != null) {
					for (DefectDictDTO defect : result) {
						defectsData.addRecord(new EstimatesSymptomsRecord(defect.getDefectName(),
								new Double(NumberFormat.getFormat("#.##").format((double) defect.getDefectConfidence()))
								));
					}
					defectsGrid.setData(defectsData.getRecords().toArray
							(new EstimatesSymptomsRecord[defectsData.getRecords().size()]));
				}
			}
		};

		dataGetterAsc.getPossibleDefects(object, estimateSymptomsData.getRecordsAsSymptoms(), callback);
	}
	
	private void saveEstimate( EstimateDTO newEstimate, List<SymptomDTO> symptoms ) {
		if (dataGetterAsc == null) {
			dataGetterAsc = GWT.create(DataGetterService.class);
		}

		AsyncCallback<Boolean> callback = new AsyncCallback<Boolean>() {
			public void onFailure(Throwable caught) {
				System.out.println(caught.getMessage());
			}

			public void onSuccess(Boolean result) {
				if(result) {
					parentLayout.refreshObjectEstimates(object.getId());
					window.destroy();
				}
				else
					com.google.gwt.user.client.Window.alert("Błąd zapisu");
			}
		};
		dataGetterAsc.saveNewEstimate(newEstimate, symptoms, callback);
	}
}

class EstimatesSymptomsRecord extends ListGridRecord {

	private static int index = -1;

	EstimatesSymptomsRecord() {}
	EstimatesSymptomsRecord( String symptom, double confidence ) {
		index++;
		setSymptom(symptom);
		setConfidence(confidence);
	}

	public void setSymptom( String symptom ) {
		this.setAttribute("symptom", symptom);
	}

	public void setConfidence( double confidence ) {
		this.setAttribute("confidence", confidence);
	}

	public String getFieldValue(String field) {
		return getAttributeAsString(field);
	}

	public int getIndex() {
		return index;
	}

}

class EstimateSymptomsData {

	private ArrayList<EstimatesSymptomsRecord> records;

	EstimateSymptomsData() {
		records = new ArrayList<EstimatesSymptomsRecord>();
	}

	public void clearRecords() {
		records.clear();
	}

	public void addRecord(EstimatesSymptomsRecord estimatesSymptomsRecord) {
		int index = findSyptom(estimatesSymptomsRecord);
		if(index > 0)
			records.set(index-1, estimatesSymptomsRecord);
		else
			records.add(estimatesSymptomsRecord);
	}

	public ArrayList<EstimatesSymptomsRecord> getRecords() {
		return records;
	}

	public EstimatesSymptomsRecord getRecord(int index) {
		return records.get(index);
	}

	public void removeRecord(int index) {
		records.remove(index);
	}

	public int findSyptom(EstimatesSymptomsRecord newRecord) {
		int i = 0;
		for(EstimatesSymptomsRecord record : records) {
			i++;
			if( record.getFieldValue("symptom").equals(newRecord.getFieldValue("symptom")) )
				return i;
		}
		return 0;
	}
	
	public List<SymptomDTO> getRecordsAsSymptoms() {
		ArrayList<SymptomDTO> symptoms = new ArrayList<SymptomDTO>();
		for(EstimatesSymptomsRecord record : records) {
			symptoms.add(new SymptomDTO(record.getFieldValue("symptom"),
					                    Double.parseDouble(record.getFieldValue("confidence"))));
		}

		return symptoms;
	}
}